#include "pch.h"

#define box2d_frame_time_interval  1.f / 60.f
b2BodySmart::~b2BodySmart()
{	
	if(body)
	{
		void* data = body->GetUserData();
		if(data)
		{
			delete data;
		}

		Box2DManager::Instance()->GetWorld()->DestroyBody(body);
	}	
}

class QueryCallback : public b2QueryCallback
{
public:
	QueryCallback(const b2Vec2& point)
	{
		m_point = point;
		m_fixture = NULL;
	}

	bool ReportFixture(b2Fixture* fixture)
	{
		b2Body* body = fixture->GetBody();
		if (body->GetType() == b2_dynamicBody)
		{
			bool inside = fixture->TestPoint(m_point);
			if (inside)
			{
				m_fixture = fixture;

				// We are done, terminate the query.
				return false;
			}
		}

		// Continue the query.
		return true;
	}

	b2Vec2 m_point;
	b2Fixture* m_fixture;
};



Box2DManager::Box2DManager():m_world(NULL)
							,m_enableGravrity(false)
{
	//m_debugDraw = new Box2DDebugDraw();

	b2Vec2 gravity;
	gravity.Set(0.0f, 0.0f);
	m_world = new b2World(gravity);
}

Box2DManager::~Box2DManager()
{
	delete m_world;
	m_world = NULL;
}

void Box2DManager::SetContactListener(b2ContactListener* listener)
{
	m_world->SetContactListener(listener);
}

b2World* Box2DManager::GetWorld()
{
	return m_world;
}

void Box2DManager::SetEnableGravrity(bool flag)
{
	if(m_enableGravrity != flag)
	{
		m_world->SetAllowSleeping(false);
		m_enableGravrity = flag;
		if(flag)
		{
			m_world->SetGravity(b2Vec2(0, -10.f));
		}
		else
		{
			m_world->SetGravity(b2Vec2(0, 0.f));
		}		
		m_world->SetAllowSleeping(true);
	}
}

bool Box2DManager::IsEnableGravrity()
{
	return m_enableGravrity;
}

void Box2DManager::OnUpdate(float frameTime)
{
	static float frame_time_counter = 0.f;

	frame_time_counter += frameTime;
	while (frame_time_counter > box2d_frame_time_interval)
	{
		frame_time_counter -= box2d_frame_time_interval;
		m_world->Step(box2d_frame_time_interval, 6, 2);
	}
	//char a[32];
	//sprintf_s(a, "%f\n", frameTime);
	//OutputDebugStringA(a);
}

void Box2DManager::OnPreRender()
{
	
}

void Box2DManager::CreateBox(const BodyInfo& creator_info, b2BodySmart& sbody, const b2Transform& transform, const b2Vec2& size, float density)
{
	b2BodyDef bd;
	bd.type = creator_info.entity_bodytype;
	bd.position.Set(transform.p.x, transform.p.y);
	bd.angle = transform.q.GetAngle();
	b2Body* body = m_world->CreateBody(&bd);

	b2PolygonShape shape;
	shape.SetAsBox(size.x, size.y);

	b2FixtureDef fd;
	fd.shape = &shape;
	fd.density = density;
	body->CreateFixture(&fd);

	BodyInfo* info = new BodyInfo(creator_info);
	info->uid = GenerateKey();

	body->SetUserData(info);
	body->SetActive(false);

	sbody.body = body;
}

void Box2DManager::CretateCircle(const BodyInfo& creator_info, b2BodySmart& sbody, const b2Transform& transform, float radius, float density, float friction)
{
	b2BodyDef bd;
	bd.type = b2_dynamicBody;
	bd.position.Set(transform.p.x, transform.p.y);


	b2Body* body = m_world->CreateBody(&bd);

	b2CircleShape circle;
	circle.m_radius = 2.f;


	b2FixtureDef fd;
	fd.shape = &circle;
	fd.density = radius;
	fd.friction = friction;
	body->CreateFixture(&fd);

	BodyInfo* info = new BodyInfo(creator_info);
	info->uid = GenerateKey();

	body->SetUserData(info);
	body->SetActive(false);

	sbody.body = body;
}

void Box2DManager::CreateJoint(const b2BodySmart& pA, const b2BodySmart& pB, b2RevoluteJointDef& jd)
{
	jd.Initialize(pA.body, pB.body, pA.body->GetPosition());

	m_world->CreateJoint(&jd);
}
